﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.Shell;
using VSIXUtilities.Helpers;
using VSIXUtilities.Helpers.Extensions;
using EnvDTE;
using VSIXUtilities.EventsListeners;
using VSIXUtilities.DataObjects;
using Microsoft.VisualStudio;

namespace VSIXUtilities.Loggers
{
	public class ErrorListLogger : IDisposable
	{
		ErrorListProvider ErrorListProviderInstance;
        VsSolutionEvents VsSolutionEventsInstance = new VsSolutionEvents();
        Hashtable<string, List<ErrorTask>> HashtableOfProjectsErrors;
        public ErrorListLogger(string ProviderName)
        {
            ErrorListProviderInstance = new ErrorListProvider(ServiceProvider.GlobalProvider)
            {
                ProviderName = ProviderName
            };
            VsSolutionEventsInstance.BeforeUnloadProject += new ProjectSimpleEventHandler(VsSolutionEventsInstance_BeforeUnloadProject);
            VsSolutionEventsInstance.BeforeCloseProject += new ProjectSimpleEventHandler(VsSolutionEventsInstance_BeforeCloseProject);
            HashtableOfProjectsErrors = new Hashtable<string, List<ErrorTask>>();
        }

        private void VsSolutionEventsInstance_BeforeCloseProject(Microsoft.VisualStudio.Shell.Interop.IVsHierarchy EntityHierarchy)
        {
            ClearProjectTasks(new IVsHierarchyWrapper(EntityHierarchy, VSConstants.VSITEMID_ROOT).Caption);
        }

        private void VsSolutionEventsInstance_BeforeUnloadProject(Microsoft.VisualStudio.Shell.Interop.IVsHierarchy EntityHierarchy)
        {
            ClearProjectTasks(new IVsHierarchyWrapper(EntityHierarchy, VSConstants.VSITEMID_ROOT).Caption);
        }

        public void Log(string Message, TaskErrorCategory Category, string RelatedProjectName)
        {
            DebugHelper.LogCall();
            if (string.IsNullOrEmpty(Message))
            {
                return;
            }
            Log(new ErrorTask()
            {
                CanDelete = false,
                ErrorCategory = Category,
                Text = Message,
            }, RelatedProjectName);
        }

        public void Log(string Message, TaskErrorCategory Category, ProjectItem ProjectItemInstance, bool CanBeDeleted, EventHandler HelpEventHandler)
        {
            DebugHelper.LogCall();
            if (string.IsNullOrEmpty(Message))
            {
                return;
            }
            ErrorTask ErrorTaskInstance = new ErrorTask()
            {
                CanDelete = CanBeDeleted,
                ErrorCategory = Category,
                Document = ProjectItemInstance.Document.FullName,
                //Document = ProjectItemInstance.FileNames[0],
                Line = 0,
                Column = 0,
                HierarchyItem = ProjectItemInstance.ToIVsHierarchyWrapper().Hierarchy,
                Text = Message,
            };
            ErrorTaskInstance.Navigate += new EventHandler(delegate(object sender, EventArgs e)
            {
                ErrorListProviderInstance.Navigate((ErrorTask)sender, new Guid(Constants.vsViewKindCode));
            });
            if (HelpEventHandler != null)
            {
                ErrorTaskInstance.Help += HelpEventHandler;
            }
            Log(ErrorTaskInstance, ProjectItemInstance.ContainingProject.Name);
        }

        public void Log(Exception Ex, string RelatedProjectName)
		{
			DebugHelper.LogCall();
			if(Ex == null)
			{
				return;
			}
            Log(new ErrorTask(Ex)
			{
				CanDelete = false,
				ErrorCategory = TaskErrorCategory.Error,
				Text = Ex.Message, 
			}, RelatedProjectName);
		}

        private void Log(ErrorTask ErrorTaskInstance, string RelatedProjectName)
        {
            if (ErrorListProviderInstance == null)
            {
                return;
            }
            ErrorListProviderInstance.Show();
            ErrorListProviderInstance.Tasks.Add(ErrorTaskInstance);
            if (!string.IsNullOrEmpty(RelatedProjectName))
            {
                if(HashtableOfProjectsErrors[RelatedProjectName] == null)
                {
                    HashtableOfProjectsErrors[RelatedProjectName] = new List<ErrorTask>();
                }
                HashtableOfProjectsErrors[RelatedProjectName].Add(ErrorTaskInstance);
            }
        }

        private void ClearProjectTasks(string ProjectName)
        {
            foreach (ErrorTask ErrorTaskToBeRemoved in HashtableOfProjectsErrors[ProjectName])
            {
                ErrorListProviderInstance.Tasks.Remove(ErrorTaskToBeRemoved);
            }
            HashtableOfProjectsErrors[ProjectName].Clear();
        }

		public void Clear()
		{
			ErrorListProviderInstance.Tasks.Clear();
		}

        #region IDisposable Members

        public void Dispose()
        {
            VsSolutionEventsInstance.Dispose();
        }

        #endregion
    }
}
